Grails的验证功能基于Spring's Validator API和数据绑定功能。
不过,Grails利用这些特性,通过它的"constraints(约束)"机制, 提供了一个统一的定义验证约束方式。
Grails中的Constraints(约束)是用声明式指定效验规则的方式。常用于domain 类,不过 URL
Mappings 和Command 对象同样支持Constraints(约束)。
在一个domain类中,constraints(约束)
是通过给constraints属性赋值代码块的形式来定义的:
class User {
String login
String password
String email
Integer age static constraints = {
…
}
}
然后,通过与属性名匹配的方法调用,并结合命名参数来指定constraints(约束)
class User {
... static constraints = {
login(size:5..15, blank:false, unique:true)
password(size:5..15, blank:false)
email(email:true, blank:false)
age(min:18, nullable:false)
}
}
在这个示例中,我们声明login
属性必须在5-15个字符长度之间,不能为空,并且必须是唯一的。
我们还可以为password
,email
和age
属性运用其他的约束.
现有约束的完整参考可以在参考指南中找到
验证基础
你可以在任何实体中调用validate方法验证domain:
def user = new User(params)if(user.validate()) {
// do something with user
}
else {
user.errors.allErrors.each {
println it
}
}
domain的errors
属性是一个Spring Errors 接口实例. Errors
提供用于导航验证错误以及取回原始值的方法。
验证阶段
Grails中本质上有2个验证阶段,第一个阶段是 data
binding ,当你把请求参数绑定到实体上发生,例如:
def user = new User(params)
这时,因为类型转换(如String转换为Dates),在errors
属性可能已经出现错误。
你可以检查它们并通过使用Errors
API获得原始输入值:
if(user.hasErrors()) {
if(user.errors.hasFieldErrors("login")) {
println user.errors.getFieldError("login").rejectedValue
}
}
验证的第2阶段发生在当你调用
validate
或 save时。
这时,Grails将会验证你在constraints
定义的约束值。比如,默认的持久方法save会在执行之前调用
validate
。因此,允许你像下面这样编码:
if(user.save()) {
return user
}
else {
user.errors.allErrors.each {
println it
}
}
显示错误
通常,当你得到一个验证错误后,你会重定向回页面渲染这些错误。这时,你就需要一些渲染错误的方法。
Grails 提供了一组丰富的标签,处理错误渲染。 如果只是想简单的渲染错误列表,可以使用renderErrors:
<g:renderErrors bean="${user}" />
假如,你需要更多的控制,可以使用 hasErrors 和 eachError:
<g:hasErrors bean="${user}">
<ul>
<g:eachError var="err" bean="${user}">
<li>${err}</li>
</g:eachError>
</ul>
</g:hasErrors>
高亮错误
当一个字段存在错误的输入时,一个红色块和一些提示符,对于高亮错误非常有用。
这时通过把 hasErrors
当做方法调用来做到。 比如:
<div class='value ${hasErrors(bean:user,field:'login','errors')}'>
<input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/>
</div>
上面的代码做了什么?它会检查user
的login
字段是否存在任何错误,如果存在,就给
div
添加一个errors
CSS class,这样就可以让你使用CSS来高亮div
.
取回输入值
任何错误实际上是Spring中FieldError 类的实体,它会在内部保存原始输入值。通过fieldValue标签获取错误对象的原始输入值:
<input type="text" name="login" value="${fieldValue(bean:user,field:'login')}"/>
这段代码会查看,在User
bean中是否存在一个 FieldError
,如果是,就获取
login
字段的原始输入值。
Grails中另一个关于errors值得注意的重要事情是:错误消息的显示,无需任何的硬编码。Spring中的
FieldError类使用Grails的
i18n
支持,基本上解决了来自消息绑定的消息。
规约与 Message 编码
编码它们自己通过规约来规定,例如,考虑早前看到约束:
package com.mycompany.myappclass User {
...
static constraints = {
login(size:5..15, blank:false, unique:true)
password(size:5..15, blank:false)
email(email:true, blank:false)
age(min:18, nullable:false)
}
}
如果 blank
约束不合法
, Grails将在form中通过规约查找消息编码:
[Class Name].[Property Name].[Constraint Code]
在这种情况下, blank
约束就会是
user.login.blank
因此,你需要在
grails-app/i18n/messages.properties
文件中包含下面这样的消息:
user.login.blank=Your login name must be specified!
它会查找带package或不带package的类名,带有package的将会优先。作为示例,com.mycompany.myapp.User.login.blank 将先于
user.login.blank使用。 当你domain 类的消息编码与插件产生冲突时,可以这样使用。
每个规约的编码参考可以参考参考指南
constraints refer to the reference guide for each constraint.
显示消息
当你使用message标签时, renderErrors 标签将自动处理查找消息。
不过,假如你想获得更多的渲染控制,你需要自己编写代码:
<g:hasErrors bean="${user}">
<ul>
<g:eachError var="err" bean="${user}">
<li><g:message error="${err}" /></li>
</g:eachError>
</ul>
</g:hasErrors>
这个示例中, eachError 标签主体内,我们使用了
message 标签的 error
参数来读取给定的错误 。
Domain 类与
command
objects(命令行对象)默认支持验证。其他类也可以在类中定义静态constraints 属性获得验证(如上所述),然后把它们告诉框架。 当应用程序在框架中注册验证类 是非常重要的
。简单定义constraints属性是不够的。
Validateable 注解
任何定义了静态constraints属性和标有
@Validateable 接口的类可以在框架中被验证。
考虑下面示例:
// src/groovy/com/mycompany/myapp/User.groovy
package com.mycompany.myappimport org.codehaus.groovy.grails.validation.Validateable
@Validateable
class User {
...
static constraints = {
login(size:5..15, blank:false, unique:true)
password(size:5..15, blank:false)
email(email:true, blank:false)
age(min:18, nullable:false)
}
}
默认情况下,框架会搜索所有带有@Validateable 注解的类。
你可以指定框架只搜索某个packages,通过给Config.groovy中的
grails.validateable.packages属性赋值一列字符串。
// grails-app/conf/Config.groovy...
grails.validateable.packages = ['com.mycompany.dto', 'com.mycompany.util']
...
假如grails.validateable.packages属性被设置,框架只会在这些packages中搜索 (和它们的子
packages) 标有@Validateable的类.
注册Validateable类
假如一个类没有被标为@Validateable,它仍然可能通过框架验证。 那就是必须在类中定义静态constraints 属性 (如上所述) ,
然后,通过在Config.groovy中为grails.validateable.classes属性设置值来告诉框架。
// grails-app/conf/Config.groovy...
grails.validateable.classes = [com.mycompany.myapp.User, com.mycompany.dto.Account]
...